import unittest
import os
import sys
from datetime import datetime, timedelta
from typing import Dict, Any, List

# 添加项目根目录到Python路径
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(project_root)

from dao.email_dao import EmailDao

class TestEmailDao(unittest.TestCase):
    """EmailDao类的单元测试"""
    
    @classmethod
    def setUpClass(cls):
        """测试类初始化"""
        conf_file = os.path.join(project_root, "conf", "dao_config.toml")
        cls.dao = EmailDao(conf_file)
        cls.test_table = cls.dao.table_name
        
        # 测试数据
        cls.sample_email_data = {
            'uid': 'test_email_001',
            'entrust_no': 'TEST_ENT_001',
            'subject': '测试邮件主题',
            'sender': 'test@example.com',
            'email_date': datetime.now(),
            'ship_name': 'TEST SHIP',
            'voyage': 'TEST001',
            'processing_status': 'pending',
            'ai_response': {'test': 'data', 'status': 'success'},
            'attachments': [{'name': 'test.pdf', 'size': 2048}]
        }
        
        cls.sample_email_data_2 = {
            'uid': 'test_email_002',
            'entrust_no': 'TEST_ENT_002',
            'subject': '测试邮件主题2',
            'sender': 'test2@example.com',
            'email_date': datetime.now() - timedelta(days=1),
            'ship_name': 'TEST SHIP 2',
            'voyage': 'TEST002',
            'processing_status': 'completed',
            'ai_response': {'test': 'data2', 'status': 'completed'},
            'attachments': []
        }
    
    def setUp(self):
        """每个测试方法执行前的准备"""
        # 清理测试数据
        self.cleanup_test_data()
    
    def tearDown(self):
        """每个测试方法执行后的清理"""
        # 清理测试数据
        self.cleanup_test_data()
    
    def cleanup_test_data(self):
        """清理测试数据"""
        try:
            # 删除测试数据
            test_uids = ['test_email_001', 'test_email_002', 'test_email_003']
            self.dao.delete_by_ids(test_uids, id_field='uid')
        except Exception as e:
            print(f"清理测试数据时出错: {e}")
    
    def test_01_save_single_record(self):
        """测试保存单条记录"""
        print("\n=== 测试保存单条记录 ===")
        
        # 测试保存
        result = self.dao.save(self.sample_email_data)
        self.assertTrue(result, "保存单条记录应该成功")
        
        # 验证数据是否保存成功
        query_result = self.dao.query(conditions={'uid': 'test_email_001'})
        self.assertEqual(len(query_result), 1, "应该查询到一条记录")
        self.assertEqual(query_result[0]['uid'], 'test_email_001')
        
        print(f"✓ 成功保存记录: {query_result[0]['uid']}")
    
    def test_02_save_duplicate_record(self):
        """测试保存重复记录（更新）"""
        print("\n=== 测试保存重复记录 ===")
        
        # 先保存一条记录
        self.dao.save(self.sample_email_data)
        
        # 修改数据并再次保存
        updated_data = self.sample_email_data.copy()
        updated_data['subject'] = '更新后的主题'
        updated_data['processing_status'] = 'completed'
        
        result = self.dao.save(updated_data)
        self.assertTrue(result, "更新记录应该成功")
        
        # 验证更新
        query_result = self.dao.query(conditions={'uid': 'test_email_001'})
        self.assertEqual(len(query_result), 1, "应该只有一条记录")
        self.assertEqual(query_result[0]['subject'], '更新后的主题')
        self.assertEqual(query_result[0]['processing_status'], 'completed')
        
        print(f"✓ 成功更新记录: {query_result[0]['subject']}")
    
    def test_03_query_basic(self):
        """测试基本查询功能"""
        print("\n=== 测试基本查询功能 ===")
        
        # 先保存测试数据
        self.dao.save(self.sample_email_data)
        self.dao.save(self.sample_email_data_2)
        
        # 测试查询所有记录
        all_results = self.dao.query()
        self.assertGreaterEqual(len(all_results), 2, "应该至少有2条记录")
        
        # 测试条件查询
        condition_results = self.dao.query(conditions={'processing_status': 'pending'})
        self.assertGreater(len(condition_results), 0, "应该查询到pending状态的记录")
        
        # 测试字段选择
        field_results = self.dao.query(
            select_fields=['uid', 'subject'],
            conditions={'uid': 'test_email_001'}
        )
        self.assertEqual(len(field_results), 1)
        self.assertIn('uid', field_results[0])
        self.assertIn('subject', field_results[0])
        
        print(f"✓ 查询测试通过，共查询到 {len(all_results)} 条记录")
    
    def test_04_query_advanced(self):
        """测试高级查询功能"""
        print("\n=== 测试高级查询功能 ===")
        
        # 保存测试数据
        self.dao.save(self.sample_email_data)
        self.dao.save(self.sample_email_data_2)
        
        # 测试IN查询
        in_results = self.dao.query(conditions={
            'uid': ['test_email_001', 'test_email_002']
        })
        self.assertEqual(len(in_results), 2, "IN查询应该返回2条记录")
        
        # 测试LIKE查询
        like_results = self.dao.query(conditions={
            'subject': '%测试邮件%'
        })
        self.assertGreaterEqual(len(like_results), 2, "LIKE查询应该返回匹配的记录")
        
        # 测试排序和限制
        sorted_results = self.dao.query(
            order_by='email_date DESC',
            limit=1
        )
        self.assertEqual(len(sorted_results), 1, "限制查询应该返回1条记录")
        
        print(f"✓ 高级查询测试通过")
    
    def test_05_count_records(self):
        """测试记录计数功能"""
        print("\n=== 测试记录计数功能 ===")
        
        # 保存测试数据
        self.dao.save(self.sample_email_data)
        self.dao.save(self.sample_email_data_2)
        
        # 测试总数统计
        total_count = self.dao.count()
        self.assertGreaterEqual(total_count, 2, "总记录数应该至少为2")
        
        # 测试条件统计
        pending_count = self.dao.count(conditions={'processing_status': 'pending'})
        completed_count = self.dao.count(conditions={'processing_status': 'completed'})
        
        self.assertGreaterEqual(pending_count, 1, "pending状态记录应该至少1条")
        self.assertGreaterEqual(completed_count, 1, "completed状态记录应该至少1条")
        
        print(f"✓ 计数测试通过: 总数={total_count}, pending={pending_count}, completed={completed_count}")
    
    def test_06_batch_save(self):
        """测试批量保存功能"""
        print("\n=== 测试批量保存功能 ===")
        
        # 准备批量数据
        batch_data = [
            self.sample_email_data,
            self.sample_email_data_2,
            {
                'uid': 'test_email_003',
                'entrust_no': 'TEST_ENT_003',
                'subject': '批量测试邮件',
                'sender': 'batch@example.com',
                'email_date': datetime.now(),
                'processing_status': 'pending'
            }
        ]
        
        # 执行批量保存
        result = self.dao.batch_save(batch_data)
        
        self.assertTrue(result['success_count'] >= 3, "应该成功保存至少3条记录")
        self.assertEqual(result['failed_count'], 0, "失败数量应该为0")
        
        # 验证批量保存结果
        saved_count = self.dao.count(conditions={
            'uid': ['test_email_001', 'test_email_002', 'test_email_003']
        })
        self.assertEqual(saved_count, 3, "应该保存3条记录")
        
        print(f"✓ 批量保存测试通过: 成功={result['success_count']}, 失败={result['failed_count']}")
    
    def test_07_update_records(self):
        """测试更新记录功能"""
        print("\n=== 测试更新记录功能 ===")
        
        # 先保存测试数据
        self.dao.save(self.sample_email_data)
        self.dao.save(self.sample_email_data_2)
        
        # 测试单条更新
        update_result = self.dao.update(
            update_data={'processing_status': 'processed', 'subject': '已更新的主题'},
            conditions={'uid': 'test_email_001'}
        )
        
        self.assertTrue(update_result['success'], "更新应该成功")
        self.assertEqual(update_result['affected_rows'], 1, "应该影响1行")
        
        # 验证更新结果
        updated_record = self.dao.query(conditions={'uid': 'test_email_001'})[0]
        self.assertEqual(updated_record['processing_status'], 'processed')
        self.assertEqual(updated_record['subject'], '已更新的主题')
        
        # 测试批量更新
        batch_update_result = self.dao.update(
            update_data={'processing_status': 'archived'},
            conditions={'uid': ['test_email_001', 'test_email_002']}
        )
        
        self.assertTrue(batch_update_result['success'], "批量更新应该成功")
        self.assertEqual(batch_update_result['affected_rows'], 2, "应该影响2行")
        
        print(f"✓ 更新测试通过: 单条更新影响{update_result['affected_rows']}行, 批量更新影响{batch_update_result['affected_rows']}行")
    
    def test_08_delete_by_ids(self):
        """测试根据ID删除记录"""
        print("\n=== 测试根据ID删除记录 ===")
        
        # 先保存测试数据
        self.dao.save(self.sample_email_data)
        self.dao.save(self.sample_email_data_2)
        
        # 测试单个ID删除
        delete_result = self.dao.delete_by_ids('test_email_001', id_field='uid')
        
        self.assertTrue(delete_result['success'], "删除应该成功")
        self.assertEqual(delete_result['deleted_count'], 1, "应该删除1条记录")
        
        # 验证删除结果
        remaining_count = self.dao.count(conditions={'uid': 'test_email_001'})
        self.assertEqual(remaining_count, 0, "记录应该被删除")
        
        # 测试批量ID删除
        # 重新保存数据
        self.dao.save(self.sample_email_data)
        
        batch_delete_result = self.dao.delete_by_ids(
            ['test_email_001', 'test_email_002'], 
            id_field='uid'
        )
        
        self.assertTrue(batch_delete_result['success'], "批量删除应该成功")
        self.assertEqual(batch_delete_result['deleted_count'], 2, "应该删除2条记录")
        
        print(f"✓ ID删除测试通过: 单条删除{delete_result['deleted_count']}条, 批量删除{batch_delete_result['deleted_count']}条")
    
    def test_09_delete_by_conditions(self):
        """测试根据条件删除记录"""
        print("\n=== 测试根据条件删除记录 ===")
        
        # 先保存测试数据
        self.dao.save(self.sample_email_data)
        self.dao.save(self.sample_email_data_2)
        
        # 测试条件删除
        delete_result = self.dao.delete_by_conditions({
            'processing_status': 'pending'
        })
        
        self.assertTrue(delete_result['success'], "条件删除应该成功")
        self.assertGreaterEqual(delete_result['deleted_count'], 1, "应该删除至少1条记录")
        
        # 验证删除结果
        remaining_pending = self.dao.count(conditions={'processing_status': 'pending'})
        self.assertEqual(remaining_pending, 0, "pending状态的记录应该被删除")
        
        print(f"✓ 条件删除测试通过: 删除了{delete_result['deleted_count']}条记录")
    
    def test_10_error_handling(self):
        """测试错误处理"""
        print("\n=== 测试错误处理 ===")
        
        # 测试空数据保存
        empty_result = self.dao.save({})
        self.assertFalse(empty_result, "空数据保存应该失败")
        
        # 测试空条件更新
        empty_update_result = self.dao.update(
            update_data={'status': 'test'},
            conditions={}
        )
        self.assertFalse(empty_update_result['success'], "空条件更新应该失败")
        
        # 测试空条件删除
        empty_delete_result = self.dao.delete_by_conditions({})
        self.assertFalse(empty_delete_result['success'], "空条件删除应该失败")
        
        # 测试空ID列表删除
        empty_ids_result = self.dao.delete_by_ids([], id_field='uid')
        self.assertFalse(empty_ids_result['success'], "空ID列表删除应该失败")
        
        print("✓ 错误处理测试通过")
    
    def test_11_data_validation(self):
        """测试数据验证功能"""
        print("\n=== 测试数据验证功能 ===")
        
        # 测试JSON数据处理
        json_data = self.sample_email_data.copy()
        json_data['ai_response'] = {'complex': {'nested': 'data'}, 'array': [1, 2, 3]}
        
        result = self.dao.save(json_data)
        self.assertTrue(result, "JSON数据保存应该成功")
        
        # 验证JSON数据
        saved_record = self.dao.query(conditions={'uid': 'test_email_001'})[0]
        self.assertIsInstance(saved_record['ai_response'], str, "JSON字段应该被序列化为字符串")
        
        # 测试日期时间处理
        datetime_data = self.sample_email_data.copy()
        datetime_data['email_date'] = '2024-01-01T10:00:00'
        
        result = self.dao.save(datetime_data)
        self.assertTrue(result, "日期时间数据保存应该成功")
        
        print("✓ 数据验证测试通过")
    
    def test_12_config_and_properties(self):
        """测试配置和属性"""
        print("\n=== 测试配置和属性 ===")
        
        # 测试表名属性
        table_name = self.dao.table_name
        self.assertIsInstance(table_name, str, "表名应该是字符串")
        self.assertGreater(len(table_name), 0, "表名不应该为空")
        
        # 测试配置重载
        try:
            self.dao.reload_config()
            print("✓ 配置重载成功")
        except Exception as e:
            self.fail(f"配置重载失败: {e}")
        
        print(f"✓ 配置测试通过: 表名={table_name}")

def run_performance_test():
    """性能测试"""
    print("\n" + "="*50)
    print("开始性能测试")
    print("="*50)
    
    project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    conf_file = os.path.join(project_root, "conf", "dao_config.toml")
    dao = EmailDao(conf_file)
    
    # 清理测试数据
    dao.delete_by_conditions({'uid': '%perf_test%'})
    
    # 生成大量测试数据
    batch_size = 100
    batch_data = []
    
    for i in range(batch_size):
        data = {
            'uid': f'perf_test_{i:04d}',
            'entrust_no': f'PERF_{i:04d}',
            'subject': f'性能测试邮件 {i}',
            'sender': f'perf{i}@example.com',
            'email_date': datetime.now() - timedelta(minutes=i),
            'processing_status': 'pending' if i % 2 == 0 else 'completed',
            'ai_response': {'test_id': i, 'batch': 'performance'}
        }
        batch_data.append(data)
    
    # 测试批量插入性能
    start_time = datetime.now()
    result = dao.batch_save(batch_data)
    insert_time = (datetime.now() - start_time).total_seconds()
    
    print(f"批量插入 {batch_size} 条记录耗时: {insert_time:.2f}秒")
    print(f"插入成功: {result['success_count']}, 失败: {result['failed_count']}")
    
    # 测试查询性能
    start_time = datetime.now()
    query_result = dao.query(conditions={'processing_status': 'pending'})
    query_time = (datetime.now() - start_time).total_seconds()
    
    print(f"条件查询耗时: {query_time:.2f}秒，查询到 {len(query_result)} 条记录")
    
    # 测试更新性能
    start_time = datetime.now()
    update_result = dao.update(
        update_data={'processing_status': 'processed'},
        conditions={'processing_status': 'pending'}
    )
    update_time = (datetime.now() - start_time).total_seconds()
    
    print(f"批量更新耗时: {update_time:.2f}秒，更新了 {update_result['affected_rows']} 条记录")
    
    # 测试删除性能
    start_time = datetime.now()
    delete_result = dao.delete_by_conditions({'uid': '%perf_test%'})
    delete_time = (datetime.now() - start_time).total_seconds()
    
    print(f"批量删除耗时: {delete_time:.2f}秒，删除了 {delete_result['deleted_count']} 条记录")
    
    print("\n性能测试完成")

if __name__ == '__main__':
    print("EmailDao 单元测试")
    print("="*50)
    
    # 运行单元测试
    unittest.main(argv=[''], exit=False, verbosity=2)
    
    # 运行性能测试
    try:
        run_performance_test()
    except Exception as e:
        print(f"性能测试失败: {e}")
    
    print("\n所有测试完成！")